/* File: MateStrategy.java
 * Purpose: Defines an organism's algorithm for mating
 * Author: Team Karp
 * Date: 12/13/07
 * Revisions: 12/13/07, Adam Patterson - Initial Version
 *           [2008-01-22, Adam Patterson - Implemented scripting function]
 * Additional Requirements: 
 */
package protovitae.data;

import java.util.*;
import javax.script.*;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

/**
 * @version 1.0
 * @created 06-Dec-2007 16:19:09
 */
public class MateStrategy extends GeneActionStrategy {

    public MateStrategy() {

    }

    /**
     * This method is called to execute the GeneActionStrategy.
     * 
     */
    public Object execute(Object information, ConcreteOrganism parent) {
        List<ConcreteOrganism> children = new ArrayList<ConcreteOrganism>();

        Double childCount;

        if (actionScript != null) {
            try {
                //javascript default for numbers is returning a Double
                childCount = (Double) actionScript.invokeFunction("mate", (ConcreteOrganism) information, parent,this);
            } catch (NoSuchMethodException nsme) {
                nsme.printStackTrace();
                childCount = new Double(0);
            } catch (ScriptException se) {
                se.printStackTrace();
                childCount = new Double(0);
            } catch (Exception e) {
                e.printStackTrace();
                childCount = new Double(0);
            }
        } else {
            childCount = new Double(0);
        }

        System.out.println(childCount);

        return children;
    }

    /**
     * 
     * @param parent
     */
    public void save(Element parentElm, Document doc) {
        Element mate = doc.createElement("mate"); //AYE MATE!
        
        Element xmlcode = doc.createElement("code");
        xmlcode.appendChild(doc.createTextNode(code));
        mate.appendChild(xmlcode);
        
        //Write genetic byte array
        Element gene = doc.createElement("genedata");
        for(Byte thebyte : geneticInformation){
            Element belm = doc.createElement("b");
            gene.appendChild(doc.createTextNode(thebyte.toString()));
            gene.appendChild(belm);
        }
        mate.appendChild(gene);
        
        parentElm.appendChild(mate);
    }

    public void load(Element input) {
        try{
            NodeList myroot = input.getElementsByTagName("mate");
            NodeList mycode = ((Element)myroot.item(0)).getElementsByTagName("code");
            NodeList mydata = ((Element)myroot.item(0)).getElementsByTagName("genedata");
            
            parse(mycode.item(0).getTextContent()); //Calling parse will throw an exception for us if bad code. This is good.
            for(int i=0; i<mydata.getLength(); i++){
                if(mydata.item(i).getNodeName().equals("b"))
                   geneticInformation.add(new Byte(Byte.parseByte(mydata.item(i).getTextContent())));
            }
        }
        catch(Exception e){
            e.printStackTrace(); //A bug occured
        }
    }

    
    
    /**
     * This parses the code string and stores it in param code.
     * @param code
     * @throws javax.script.ScriptException
     */
    public void parse(String code) throws ScriptException {
        ScriptEngineManager mgr = new ScriptEngineManager();
        ScriptEngine jsEngine = mgr.getEngineByName("JavaScript");

        //load the code into a function with parameters to use
        String scriptedFunctionality = "";
        scriptedFunctionality += "function mate(partner,parent,gene) {";
        scriptedFunctionality += code;
        scriptedFunctionality += "}";

        if(code != null){
            jsEngine.eval(scriptedFunctionality);
            actionScript = (Invocable) jsEngine;
        }
        else
            actionScript = null;
        this.code = code;
    }
}
